package cfig.ota

import cfig.toolset.AdbTool
import org.apache.commons.exec.CommandLine
import org.apache.commons.exec.DefaultExecutor
import org.slf4j.LoggerFactory
import se.vidstige.jadb.JadbDevice
import se.vidstige.jadb.RemoteFile
import java.io.File
import java.net.URI
import java.net.URL

@ExperimentalStdlibApi
class UpdatePkgAB(val fileName: String, var theUri: String? = null) {
    private val log = LoggerFactory.getLogger(UpdatePkgAB::class.java)

    var payloadSize: Long = -1L
    var payloadOffset: Long = -1L
    var payloadProps: String = ""

    init {
        val zf = org.apache.commons.compress.archivers.zip.ZipFile(fileName)
        val payloadBin = zf.getEntry("payload.bin")
        assert(payloadBin != null)
        log.info("probling payload.bin")
        payloadOffset = payloadBin.dataOffset
        payloadSize = payloadBin.size
        val payloadProp = zf.getEntry("payload_properties.txt")
        assert(payloadProp != null)
        log.info("probling payload_properties.txt")
        payloadProps = zf.getInputStream(payloadProp).readBytes().decodeToString()
    }

    fun installTo(dut: JadbDevice): Int {
        var ret: Int
        if (theUri == null) {
            val deviceLocalFileName = "/data/local/tmp/debug.zip"
            log.info("ADB pushing $fileName -> $deviceLocalFileName")
            dut.push(File(fileName), RemoteFile(deviceLocalFileName))
            val adt = AdbTool()
            adt.shellCheckCall(dut, "mv /data/local/tmp/debug.zip /data/ota_package/debug.zip")
            adt.shellCheckCall(dut, "chcon u:object_r:ota_package_file:s0 /data/ota_package/debug.zip")
            adt.shellCheckCall(dut, "chown system:cache /data/ota_package/debug.zip")
            adt.shellCheckCall(dut, "chmod 0660 /data/ota_package/debug.zip")
            theUri = "file:///data/ota_package/debug.zip"
        } else {
            log.info("Using URI, no need to push the package")
        }

        var header = "--headers=${this.payloadProps}"
        header += "USER_AGENT=Dalvik (something, something)\n"
        header += "NETWORK_ID=0"
        val cmd = CommandLine.parse("adb -s ${dut.serial} shell update_engine_client").apply {
            addArgument("--update")
            addArgument("--follow")
            addArgument("--payload=$theUri")
            addArgument("--offset=$payloadOffset")
            addArgument("--size=$payloadSize")
            addArgument(header)
        }
        StringBuilder().let { sb ->
            cmd.toStrings().forEach {
                sb.append("$it ")
            }
            log.info(sb.toString())
        }
        DefaultExecutor().apply {
            setExitValues(intArrayOf(0, 9, 51))
            ret = execute(cmd)
        }
        log.info("OTA returned " + ret)
        return ret
    }
}
